package com.kongxx.struts2study.common.factory;

/**
 * Generic Service Factory to generate or get an runtime Service instance.
 * @param <T>
 */
public class GenericServiceFactory<T> extends AbstractFactory {
	
	private static final String REAL_KEY = "RealImpl";
	private static final String MOCK_KEY = "MockImpl";
	private static final String REAL_PACKAGE_KEY = "real";
	private static final String MOCK_PACKAGE_KEY = "mock";
	
	/**
	 * Get the instance of implementation class.
	 * @param <T>
	 * @param t
	 * @return
	 * @throws InvalidateServiceException
	 */
	public <T> T getService(Class<T> t) throws InvalidateServiceException {
		if( t == null ) {
			throw new NullPointerException("The class cannot be null!");
		}
		Class<T> clazz = getImplClassName(t);
		if( clazz == null ) {
			String msg = "Cannot find the implementation for class:" + t.getName();
			throw new InvalidateServiceException(msg);
		}
		
		try {
			return clazz.newInstance();
		} catch (InstantiationException e) {
			throw new InvalidateServiceException(e);
		} catch (IllegalAccessException e) {
			throw new InvalidateServiceException(e);
		}
	}

	/**
	 * Get the implementation class.
	 * @param <T>
	 * @param t
	 * @return
	 */
	private <T> Class<T> getImplClassName(Class<T> t) {
		String packageName = t.getPackage().getName();
		String className = t.getSimpleName();
		String implPackageKey = REAL_PACKAGE_KEY;
		String implKey = REAL_KEY;
		
		if( isMock() ) {
			implKey = MOCK_KEY;
			implPackageKey = MOCK_PACKAGE_KEY;
		}
		
		String implClassName = null;
		Class<T> clazz = null;
		
		implClassName = packageName + className + implKey;
		try {
			clazz = (Class<T>)Class.forName(implClassName);
		} catch (ClassNotFoundException e) {
			// do nothing
		}
		
		if( clazz == null ) {
			try {
				implClassName = packageName + "." + implPackageKey + "."
						+ className + implKey;
				clazz = (Class<T>)Class.forName(implClassName);
			} catch (ClassNotFoundException e) {
				// do nothing
			}
		}
		return clazz;
	}
}
